﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using CultivationSkills.Skills;
using ThunderRoad;
using ThunderRoad.Skill;
using UnityEngine;
using UnityEngine.AddressableAssets;

namespace CultivationSkills.Utils;

public static class GameUtils
{
    public static List<T> ImbueCommentToHandleItem<T>() where T : Component
    {
        var list = new List<T>();
        if (!Player.local)
        {
            Debug.LogError("Player is null");
            return list;
        }

        ImbueSkillHandle(list, Player.local.handRight.ragdollHand.grabbedHandle);
        ImbueSkillHandle(list, Player.local.handLeft.ragdollHand.grabbedHandle);
        return list;
    }

    private static void ImbueSkillHandle<T>(List<T> list, Handle handle) where T : Component
    {
        if (!handle || !handle.item)
        {
            Debug.LogError("handle item is null");
            return;
        }

        var res = handle.item.GetComponent<T>();
        if (res != null)
        {
            // 已有
            Debug.Log("已有");
            list.Add(res);
            return;
        }

        Debug.Log("注入成功");
        res = handle.item.gameObject.AddComponent<T>();
        list.Add(res);
    }

    public static Transform GetPierceTransform(Item item)
    {
        var damagers = item.GetComponentsInChildren<Damager>();
        if (damagers == null || damagers.IsNullOrEmpty())
        {
            Debug.LogWarning("没找到伤害器！");
        }

        return damagers == null
            ? null
            : Array.Find(damagers, dm => dm.penetrationLength == 0 && dm.penetrationDepth > 0)?.transform;
    }

    private static readonly Dictionary<Item, Transform> ItemForwardCache = new Dictionary<Item, Transform>();

    public static Transform GetItemForwardTransform(Item item)
    {
        if (ItemForwardCache.TryGetValue(item, out var toward)) return toward;
        toward = GetPierceTransform(item);
        if (!toward)
        {
            Debug.LogWarning("投掷方向");
            toward = item.flyDirRef;
        }

        if (!toward)
        {
            Debug.LogWarning("Item May Not A Sword!");
            toward = item.spawnPoint != null ? item.spawnPoint.transform : item.transform;
        }

        Debug.Log("toward:" + toward);
        ItemForwardCache.Add(item, toward);
        return toward;
    }

    // 定义一个阈值，用于判断方向时的偏差
    private const float GetGestureDirThreshold = 0.4f;

    // 静态方法，用于判断手势动作的方向
    public static GestureDirectionType GetGestureDirection(Vector3 vector3)
    {
        // 将向量标准化
        var gestureVector = vector3.normalized;

        // 提取向量的分量
        var x = gestureVector.x;
        var y = gestureVector.y;
        var z = gestureVector.z;

        // 判断y分量的绝对值是否大于x和z分量的绝对值加上阈值
        if (Mathf.Abs(y) > Mathf.Abs(x) + GetGestureDirThreshold &&
            Mathf.Abs(y) > Mathf.Abs(z) + GetGestureDirThreshold)
        {
            // 如果是，则判断为向上或向下
            return y > 0 ? GestureDirectionType.Upward : GestureDirectionType.Downward;
        }
        else
        {
            // 如果不是，则判断为平推或倾斜推动
            return GestureDirectionType.PushOrTilt;
        }
    }

    public static void GripItem(RagdollHand ragdollHand, Item item)
    {
        item.transform.position = ragdollHand.transform.position;
        ragdollHand.Grab(item.GetMainHandle(ragdollHand.side));
    }

    public static ModOptionFloat[] AngleValueOptions = ModOptionFloat.CreateArray(10f, 100f, 1f);
    public static ModOptionFloat[] DistanceOptions = ModOptionFloat.CreateArray(0.0f, 90f, 1f);
    public static ModOptionInt[] RayCountOptions = ModOptionInt.CreateArray(2, 50, 2);

    [ModOption(name = "Check Horizontal Angle", order = 4, category = "Check Ray",
        interactionType = ModOption.InteractionType.Slider, valueSourceName = "AngleValueOptions",
        saveValue = true)]
    public static float FovAngleHorizontal = 60f;

    [ModOption(name = "Check Vertical Angle", order = 5, category = "Check Ray",
        interactionType = ModOption.InteractionType.Slider, valueSourceName = "AngleValueOptions",
        saveValue = true)]
    public static float FovAngleVertical = 60f;

    [ModOption(name = "Check Distance", order = 4, interactionType = ModOption.InteractionType.Slider,
        category = "Check Ray",
        valueSourceName = "DistanceOptions", saveValue = true)]
    public static float FovDistance = 50f;

    [ModOption(name = "Ray Count Horizontal", order = 5,
        interactionType = ModOption.InteractionType.Slider, category = "Check Ray",
        valueSourceName = "RayCountOptions", saveValue = true)]
    public static int RayCountHorizontal = 30;

    [ModOption(name = "Ray Count Vertical", order = 6,
        interactionType = ModOption.InteractionType.Slider, category = "Check Ray",
        valueSourceName = "RayCountOptions", saveValue = true)]
    public static int RayCountVertical = 4;

    public static readonly LayerMask NpcTargetMask = LayerMask.GetMask(LayerName.BodyLocomotion.ToString(),
        LayerName.NPC.ToString(),
        LayerName.Ragdoll.ToString());

    public static bool FindForwardHit(Vector3 source, Vector3 direction, LayerMask layerMask, out RaycastHit hit)
    {
        var angleStepHorizontal = FovAngleHorizontal / RayCountHorizontal;
        var angleStepVertical = FovAngleVertical / RayCountVertical;
        var halfFOVVertical = FovAngleHorizontal / 2;
        var halfFOVHorizontal = FovAngleVertical / 2;
        var origin = source;
        // 执行射线检测
        Debug.Log($"origin:{origin}, direction:{direction}");
        int i1;
        for (var i = i1 = RayCountVertical / 2; i >= 0; i--, i1++)
        {
            int j1;
            for (var j = j1 = RayCountHorizontal / 2; j >= 0; j--, j1++)
            {
                if (DoCheck(layerMask, direction, angleStepVertical, halfFOVVertical,
                        angleStepHorizontal, halfFOVHorizontal, origin, i, j, out hit) || !(i == i1 && j == j1) &&
                    DoCheck(layerMask, direction, angleStepVertical, halfFOVVertical,
                        angleStepHorizontal, halfFOVHorizontal, origin, i1, j1, out hit))
                {
                    return true;
                }
            }
        }

        hit = new RaycastHit();
        return false;
    }

    public static bool FindForwardHitNpc(Transform sourceTransform, out RaycastHit hit)
    {
        return FindForwardHit(sourceTransform.position, sourceTransform.forward, NpcTargetMask, out hit);
    }

    private static bool DoCheck(LayerMask targetMask, Vector3 direction,
        float angleStepVertical,
        float halfFOVVertical, float angleStepHorizontal, float halfFOVHorizontal, Vector3 origin, int i, int j,
        out RaycastHit hit)
    {
        // 计算当前射线的水平和垂直角度
        var angleHorizontal = -halfFOVHorizontal + angleStepHorizontal * j;
        var angleVertical = -halfFOVVertical + angleStepVertical * i;
        // 创建一个水平方向上的射线方向
        var horizontalRayDirection = Quaternion.AngleAxis(angleHorizontal, Vector3.up) * direction;
        // 应用垂直旋转
        var rayDirection = Quaternion.AngleAxis(angleVertical, Vector3.right) * horizontalRayDirection;

        // 发射射线
        var find = Physics.Raycast(origin, rayDirection, out hit, FovDistance, targetMask);
        if (find)
        {
            Debug.Log(
                $"hit:{hit},name:{hit.collider.gameObject.name},point:{hit.point},layerMask:{hit.collider.gameObject.layer}");
            Debug.Log($"origin:{origin},rayDirection:{rayDirection}, ({i}, {j});");
        }

        return find;
    }

    public static void StartCoroutine(float seconds, Action action)
    {
        Player.local.StartCoroutine(ExecuteAfterDelay(seconds, action));
    }

    private static IEnumerator ExecuteAfterDelay(float seconds, Action action)
    {
        yield return new WaitForSeconds(seconds);
        action();
    }

    public static void AlignRotate(Transform transform, Transform child, Transform target)
    {
        AlignRotate(transform, child.forward, target.forward);
    }

    public static void AlignRotate(Transform transform, Vector3 currentDir, Vector3 targetDir)
    {
        targetDir = targetDir.normalized;
        // 计算旋转角度和旋转轴
        var angle = Vector3.Angle(currentDir, targetDir);
        var axis = Vector3.Cross(currentDir, targetDir);
        // 应用旋转
        transform.Rotate(axis, angle, Space.World);
    }

    [SuppressMessage("ReSharper", "SuggestVarOrType_BuiltInTypes")]
    [SuppressMessage("ReSharper", "SuggestVarOrType_SimpleTypes")]
    public static void QuickDespawn(Item item)
    {
        if ((UnityEngine.Object)item == (UnityEngine.Object)null)
            return;
        item.ClearAllStatus();
        item.variables = new Dictionary<System.Type, AbstractEntityVariable>();
        ThunderEntity.allEntities.Remove(item);
        item.despawning = true;
        if (item.currentArea != null)
        {
            if (item.currentArea.IsSpawned)
                item.currentArea.SpawnedArea.UnRegisterItem(item);
            item.currentArea = (SpawnableArea)null;
        }

        item.SetCull(false);
        if ((bool)(UnityEngine.Object)item.audioContainerSnap)
            Catalog.ReleaseAsset<AudioContainer>(item.audioContainerSnap);
        if ((bool)(UnityEngine.Object)item.audioContainerInventory)
            Catalog.ReleaseAsset<AudioContainer>(item.audioContainerInventory);
        if ((bool)(UnityEngine.Object)item.holder)
            item.holder.UnSnap(item);
        for (int index = item.handlers.Count - 1; index >= 0; --index)
            item.handlers[index].UnGrab(false);
        if (item.isGripped)
        {
            for (int index = Creature.allActive.Count - 1; index >= 0; --index)
            {
                Creature creature = Creature.allActive[index];
                if ((UnityEngine.Object)creature.handRight.climb.gripItem == (UnityEngine.Object)item)
                    creature.handRight.climb.UnGrip();
                if ((UnityEngine.Object)creature.handLeft.climb.gripItem == (UnityEngine.Object)item)
                    creature.handLeft.climb.UnGrip();
            }
        }

        if (item.isTelekinesisGrabbed)
        {
            int count = item.handles.Count;
            for (int index = 0; index < count; ++index)
                item.handles[index].ReleaseAllTkHandlers();
        }

        int count1 = item.collisionHandlers.Count;
        for (int index = 0; index < count1; ++index)
            item.collisionHandlers[index].ClearPhysicModifiers();
        int count2 = item.collisionHandlers.Count;
        for (int index1 = 0; index1 < count2; ++index1)
        {
            CollisionHandler collisionHandler = item.collisionHandlers[index1];
            int count3 = collisionHandler.damagers.Count;
            for (int index2 = 0; index2 < count3; ++index2)
                collisionHandler.damagers[index2].UnPenetrateAll();
            for (int index3 = collisionHandler.penetratedObjects.Count - 1; index3 >= 0; --index3)
            {
                CollisionHandler penetratedObject = collisionHandler.penetratedObjects[index3];
                int count4 = penetratedObject.damagers.Count;
                for (int index4 = 0; index4 < count4; ++index4)
                    penetratedObject.damagers[index4].UnPenetrateAll();
            }
        }

        int count5 = item.imbues.Count;
        for (int index = 0; index < count5; ++index)
            item.imbues[index]?.UnloadCurrentSpell();
        foreach (Effect componentsInChild in item.GetComponentsInChildren<Effect>(true))
        {
            try
            {
                componentsInChild.Despawn();
            }
            catch (NullReferenceException ex)
            {
                Debug.LogError((object)string.Format(
                    "Could not despawn item {0} (instance of {1}) because effect {2} ({3}) despawn threw NRE.",
                    (object)item.name, (object)item.data.id, (object)componentsInChild,
                    (object)componentsInChild?.module?.rootData?.id));
                Debug.LogException((Exception)ex);
            }
        }

        int count6 = item.revealDecals.Count;
        for (int index = 0; index < count6; ++index)
        {
            RevealDecal revealDecal = item.revealDecals[index];
            if (revealDecal.revealMaterialController)
                revealDecal.revealMaterialController.Reset();
        }

        if (Item.allWorldAttached.Contains(item))
            Item.allWorldAttached.Remove(item);
        item.StopThrowing();
        item.StopFlying();
        if (item.physicBody != (PhysicBody)null)
            item.physicBody.velocity = UnityEngine.Vector3.zero;
        item.loaded = false;
        if (item.isPooled)
        {
            item.Hide(false);
            item.ReturnToPool();
        }
        else
        {
            item.gameObject.SetActive(false);
            if (item.addressableHandle.IsValid())
                Addressables.ReleaseInstance(item.addressableHandle);
            else
                UnityEngine.Object.Destroy((UnityEngine.Object)item.gameObject);
        }
        item.StopAllCoroutines();
        item.despawning = false;
    }
}

// 枚举类型，用于表示手势动作的方向
public enum GestureDirectionType
{
    Upward, // 向上
    Downward, // 向下
    PushOrTilt // 平推或倾斜推动
}